package com.kehutong.payment.util;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.coraframework.inject.Singleton;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.util.Objects;
import org.coraframework.util.secret.MD5;
import org.xml.sax.SAXException;
import com.kehutong.common.webchat.XmlUtil;

@Singleton
public class TencentSignature {
	
	static final Logger logger = LoggerFactory.getLogger(TencentSignature.class);
	
	/**
     * 签名算法
     * @param o 要参与签名的数据对象
     * @return 签名
     * @throws IllegalAccessException
     */
    public String getSign(Object o, String mchSecret) throws IllegalAccessException {
        Class<?> cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();

        ArrayList<String> valuelist = new ArrayList<String>();
        for (Field f : fields) {
            f.setAccessible(true);
            Object data = f.get(o);
            if (Objects.nonNull(data) && Objects.nonEmpty(data.toString())) {
            	valuelist.add(f.getName() + "=" + data + "&");
            }
        }
        Collections.sort(valuelist, String.CASE_INSENSITIVE_ORDER);
        
        StringBuilder sb = new StringBuilder();
        for(String value : valuelist) {
            sb.append(value);
        }
        sb.append("key=").append(mchSecret);
        
        return MD5.MD5Encode(sb.toString()).toUpperCase();
    }

    public String getSign(Map<String,Object> map, String mchSecret){
        ArrayList<String> valuelist = new ArrayList<String>();
        
        for (Map.Entry<String,Object> entry : map.entrySet()) {
            if(Objects.nonNull(entry.getValue()) && Objects.nonEmpty(entry.getValue().toString())){
            	valuelist.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        Collections.sort(valuelist, String.CASE_INSENSITIVE_ORDER);
        
        StringBuilder sb = new StringBuilder();
        for(String value : valuelist) {
            sb.append(value);
        }
        sb.append("key=").append(mchSecret);
        
        return MD5.MD5Encode(sb.toString()).toUpperCase();
    }

    /**
     * 从API返回的XML数据里面重新计算一次签名
     * @param responseString API返回的XML数据
     * @return 新鲜出炉的签名
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public String getSignFromResponseString(String responseString, String mchSecret) throws Exception {
        JSONObject map = XmlUtil.xml2JSON(responseString);
        //清掉返回数据对象里面的Sign数据（不能把这个数据也加进去进行签名），然后用签名算法进行签名
        map.put("sign", "");
        //将API返回的数据根据用签名算法进行计算新的签名，用来跟API返回的签名进行比较
        return getSign(map, mchSecret);
    }

    /**
     * 检验API返回的数据里面的签名是否合法，避免数据在传输的过程中被第三方篡改
     * @param responseString API返回的XML数据字符串
     * @return API签名是否合法
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public boolean checkIsSignValidFromResponseString(String responseString, String mchSecret) throws Exception {
    	JSONObject jsonObject = XmlUtil.xml2JSON(responseString);
    	return checkIsSignValidFromResponseString(jsonObject, mchSecret);
    }
    
    /**
     * 检验API返回的数据里面的签名是否合法，避免数据在传输的过程中被第三方篡改
     * @return API签名是否合法
     */
    public boolean checkIsSignValidFromResponseString(JSONObject jsonObject, String mchSecret) throws Exception {
        String outSign = jsonObject.getString("sign");
        if(Objects.isEmpty(outSign)){
            return false;
        }
        
        jsonObject.put("sign", ""); //清掉返回数据对象里面的Sign数据（不能把这个数据也加进去进行签名），然后用签名算法进行签名
        
        //将API返回的数据根据用签名算法进行计算新的签名，用来跟API返回的签名进行比较
        String sign = getSign(jsonObject, mchSecret);
        if(!sign.equals(outSign)){
            //签名验不过，表示这个API返回的数据有可能已经被篡改了
            return false;
        }
        
        return true;
    }
    
    private TencentSignature() {
    }

}